package com.joyance.springmvc.util;

import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Date;

import javax.crypto.Cipher;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;


public class RSACertificate {

    public static final String KEY_STORE = "JKS";

    public static final String X509 = "X.509";


    public KeyStore getKeyStore(String keystorePath, String password) throws Exception {
        KeyStore keyStore = KeyStore.getInstance(KEY_STORE);
        FileInputStream inputStream = new FileInputStream(keystorePath);
        keyStore.load(inputStream, password.toCharArray());
        inputStream.close();
        return keyStore;
    }


    public Certificate getCertificate(String keystorePath, String password, String alias) throws Exception {
        KeyStore keyStore = getKeyStore(keystorePath, password);
        Certificate certificate = keyStore.getCertificate(alias);
        return certificate;
    }


    public Certificate getCertificate(String certificatePath) throws Exception {
        FileInputStream inputStream = new FileInputStream(certificatePath);
        CertificateFactory certificateFactory = CertificateFactory.getInstance(X509);
        Certificate certificate = certificateFactory.generateCertificate(inputStream);
        inputStream.close();
        return certificate;
    }


    public PrivateKey getPrivateKey(String keystorePath, String password, String alias) throws Exception {
        KeyStore keyStore = getKeyStore(keystorePath, password);
        PrivateKey privateKey = (PrivateKey) keyStore.getKey(alias, password.toCharArray());
        return privateKey;
    }


    public PublicKey getPublicKey(String certificatePath) throws Exception {
        Certificate certificate = getCertificate(certificatePath);
        PublicKey publicKey = certificate.getPublicKey();
        return publicKey;
    }


    public byte[] encryptByPrivateKey(byte[] data, String keystorePath, String password, String alias) throws Exception {
        PrivateKey privateKey = getPrivateKey(keystorePath, password, alias);
        Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, privateKey);
        return cipher.doFinal(data);
    }


    public byte[] encryptByPublicKey(byte[] data, String certificatePath) throws Exception {
        PublicKey publicKey = getPublicKey(certificatePath);
        Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        return cipher.doFinal(data);
    }


    public byte[] decryptByPrivateKey(byte[] data, String keystorePath, String password, String alias) throws Exception {
        PrivateKey privateKey = getPrivateKey(keystorePath, password, alias);
        Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        return cipher.doFinal(data);
    }


    public byte[] decryptByPublicKey(byte[] data, String certificatePath) throws Exception {
        PublicKey publicKey = getPublicKey(certificatePath);
        Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, publicKey);
        return cipher.doFinal(data);
    }


    public boolean verifyCertificate(Date date, Certificate certificate) {
        boolean status = false;
        try {
            X509Certificate x509Certificate = (X509Certificate) certificate;
            x509Certificate.checkValidity(date);
            status = true;
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return status;
    }


    public String sign(String keystorePath, String password, String alias, byte[] data) throws Exception {
        X509Certificate x509Certificate = (X509Certificate) getCertificate(keystorePath, password, alias);
        PrivateKey privateKey = getPrivateKey(keystorePath, password, alias);
        Signature signature = Signature.getInstance(x509Certificate.getSigAlgName());
        signature.initSign(privateKey);
        signature.update(data);
        return new BASE64Encoder().encode(signature.sign());
    }


    public boolean verify(String sign, byte[] data, String certificatePath) throws Exception {
        // 获得证书
        X509Certificate x509Certificate = (X509Certificate) getCertificate(certificatePath);
        // 获得公钥
        PublicKey publicKey = x509Certificate.getPublicKey();
        Signature signature = Signature.getInstance(x509Certificate.getSigAlgName());
        signature.initVerify(publicKey);
        signature.update(data);
        return signature.verify(new BASE64Decoder().decodeBuffer(sign));
    }


    public static void main(String[] args) throws Exception {
        RSACertificate rsaCertificate = new RSACertificate();
        String data = "test_certificate";
        byte[] encrypt_byte = rsaCertificate.encryptByPrivateKey(data.getBytes(), "F:/学习资料/certificate/joyance.keystore", "123456", "joyance.com");
        System.out.println(new BASE64Encoder().encode(encrypt_byte));
        byte[] decrypt_byte = rsaCertificate.decryptByPublicKey(encrypt_byte, "F:/学习资料/certificate/joyance.cer");
        System.out.println(new String(decrypt_byte));

        String sign = rsaCertificate.sign("F:/学习资料/certificate/joyance.keystore", "123456", "joyance.com", data.getBytes());
        System.out.println(sign);
        boolean isVerify = rsaCertificate.verify(sign, data.getBytes(), "F:/学习资料/certificate/joyance.cer");
        System.out.println(isVerify);

        System.out.println(rsaCertificate.verifyCertificate(new Date(), rsaCertificate.getCertificate("F:/学习资料/certificate/joyance.cer")));
    }
}
